Imports System.Net 'for IPEndPoint
Imports System.Net.Sockets 'for sockets
''' -----------------------------------------------------------------------------
''' Project	 : Server
''' Class	 : clsSocket
''' 
''' -----------------------------------------------------------------------------
''' <summary>
''' 
''' </summary>
''' <remarks>
''' </remarks>
''' <history>
''' 	[Jason Schreckengost]	6/25/2006	Created
''' </history>
''' -----------------------------------------------------------------------------
Public Class clsSocket
    'This region holds all the variables which will be used
#Region "Variables" 'This will split parts of code for easy viewing

    'This is our main Socket which we will be using later
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    ''' 	[Jason Schreckengost]	6/25/2006	Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Private sktMain As New Socket(AddressFamily.InterNetwork, _
        SocketType.Stream, ProtocolType.Tcp)

    'This is the Endpoint with the location where we want information ran
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    ''' 	[Jason Schreckengost]	6/25/2006	Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Private ep As New IPEndPoint(IPAddress.Any, 30000)

    'This is our User array using clsUser
    'Public Users(4) As clsUser 'This needs to be changed for dynamic memory arrays
    Const SyncRoot As String = "_"
    Private thdAcceptCallback As Threading.Thread
#End Region 'Variables
#Region "Constructor/Destructor"
    Protected Overrides Sub Finalize()
        If Not thdAcceptCallback Is Nothing Then
            thdAcceptCallback.Abort()
            thdAcceptCallback = Nothing
        End If
        ep = Nothing
        'SyncLock Me.SyncRoot
        If Not sktMain Is Nothing Then
            If sktMain.Connected Then
                sktMain.Shutdown(SocketShutdown.Both)
            End If
            sktMain.Close()
        End If

        sktMain = Nothing
        'End SyncLock
    End Sub

#End Region
        'This region holds all the events which will be used
#Region "Events"

    Public Event DataSent(ByVal username As String, ByVal data As String)
    'This event will be called when the server is started
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    ''' 	[Jason Schreckengost]	6/25/2006	Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Public Event BeginListen()
    'This event will be called when a connection is accepted
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="ip"></param>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    ''' 	[Jason Schreckengost]	6/25/2006	Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Public Event ConnectionAccepted(ByVal ip As String, ByVal conID As Int32)
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="user"></param>
    ''' <param name="data"></param>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    ''' 	[Jason Schreckengost]	6/25/2006	Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Public Event DataReceived(ByVal user As clsUser, ByVal data As String)
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="user"></param>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    ''' 	[Jason Schreckengost]	6/25/2006	Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Public Event LoggedIn(ByVal user As clsUser)

#End Region
    'This region holds all the methods (Subs and Functions) which will be used
#Region "Methods" 'This will split parts of code for easy viewing
    '-------------------------------------------------------------------------------
    ' Usage: Listen()
    ' Listen(): Starts a continuous loop receiving connections
    '-------------------------------------------------------------------------------
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    ''' 	[Jason Schreckengost]	6/25/2006	Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Public Sub Listen()
        If Threading.Thread.CurrentThread.Name Is Nothing Then Threading.Thread.CurrentThread.Name = "clsSocket.Listen()"
        'Set the Socket to use our EndPoint
        sktMain.Bind(ep)

        'Open the socket to listening with a backlog. When the backlog(number of)
        'connections have been reached, busy status will be sent to the client
        sktMain.Listen(29) 'change later in project

        'Send the trigger for the Server Start
        RaiseEvent BeginListen()

        'Start the receiving loop
        Do
            'Begin Accepting the connection and retrieve the thread information
            Dim ar As IAsyncResult = sktMain.BeginAccept _
                (AddressOf acceptCallback, Nothing)

            'Pause this thread (connect) until the last connection has been accepted
            frmServer.thdMain.Suspend()

        Loop 'Receive loop

    End Sub 'Listen
    '-------------------------------------------------------------------------------
    ' Usage: None(used only in Listen())
    ' Variables passed:
    '   ar As IAsyncResult - contains all connection information for that connection
    ' acceptCallback: Accepts the current connection, stores it in the User() array,
    '           then transfers control to the User() array to begin receiving
    '-------------------------------------------------------------------------------
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="ar"></param>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    ''' 	[Jason Schreckengost]	6/25/2006	Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Private Sub acceptCallback(ByVal ar As IAsyncResult)
        thdAcceptCallback = Threading.Thread.CurrentThread
        'If ar.AsyncState Is Nothing Then Exit Sub
        If Threading.Thread.CurrentThread.Name Is Nothing Then Threading.Thread.CurrentThread.Name = "clsSocket.acceptCallback"
        Dim index As Integer = -1
        If Not Users Is Nothing Then
            index = findOpenUser()
        Else
            Exit Sub
        End If
        If index = -1 Then
            Try
                Display("An error occured when a user was accepted. Canceling this call")
            Catch
                'Do nothing.
                'This error seems to only happen during server shutdown
            End Try
        End If
        'MsgBox("ready for connect")
        'Users(index) = New clsUser(index)

        AddHandler Users(index).DataReceived, AddressOf DataRcvd
        AddHandler Users(index).LoggedIn, AddressOf Logged
        AddHandler Users(index).DataSent, AddressOf DataWasSent

        'Accept the connection and store the socket as 
        Users(index).SocketRef = sktMain.EndAccept(ar)

        frmServer.thdMain.Resume()

        'Send the trigger for an accepted connection
        'MsgBox("here")
        'Users(index).ConID = index
        RaiseEvent ConnectionAccepted(Users(index).IP, Users(index).ConID)
        'MsgBox("raised")

        'Users(index).ConID = index

        Dim bytes(4095) As Byte

        Users(index).SocketRef.BeginReceive(bytes, 0, bytes.Length, _
            SocketFlags.None, AddressOf Users(index).recvCallback, bytes)
        'Hand the control to the user class and begin receiving any data that is sent
        'Users(index).BeginRecv()

    End Sub 'acceptCallback
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="user"></param>
    ''' <param name="data"></param>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    ''' 	[Jason Schreckengost]	6/23/2006	Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Private Sub DataRcvd(ByVal user As clsUser, ByVal data As String)
        RaiseEvent DataReceived(user, data)
    End Sub
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <param name="user"></param>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    ''' 	[Jason Schreckengost]	6/23/2006	Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Private Sub Logged(ByVal user As clsUser)
        RaiseEvent LoggedIn(user)
    End Sub
    ''' -----------------------------------------------------------------------------
    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks>
    ''' </remarks>
    ''' <history>
    ''' 	[Jas]	7/26/2006	Created
    ''' </history>
    ''' -----------------------------------------------------------------------------
    Public Sub Close()
        Me.Finalize()
    End Sub
    Private Sub DataWasSent(ByVal username As String, ByVal data As String)
        RaiseEvent DataSent(username, data)
    End Sub
#End Region     'Methods
End Class 'clsSocket
